package com.senseuni.da.worker

import androidx.work.*
import com.elvishew.xlog.XLog
import com.senseuni.da.BuildConfig
import com.senseuni.da.MyApplication
import com.senseuni.da.db.AppDatabase
import com.senseuni.da.db.entity.AppLogEntity
import com.senseuni.da.http.ApiDataSource
import com.senseuni.da.model.LogType
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger

class AppLog {

    private var logCount = AtomicInteger(0)

    private val appLogDao by lazy { AppDatabase.getInstance().appLogDao() }

    companion object {
        val instance : AppLog by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            AppLog()
        }
    }

    fun init() {
        logCount.set(appLogDao.countByNeedUpload())
    }

    fun log(logType: LogType, message: String) {
        val entity = AppLogEntity()
        entity.logType = logType.name
        entity.log = message
        entity.versionCode = BuildConfig.VERSION_CODE
        entity.createTime = System.currentTimeMillis()
        appLogDao.insert(entity)
        val count = logCount.incrementAndGet()
        if (count % 10 == 0) {
            CoroutineScope(Dispatchers.IO).launch {
                uploadLogs()
            }
        }

        startWorker()

        if (count > 1000000) {
            logCount.set(0)
        }
    }

    private suspend fun uploadLogs() {
        val logs = appLogDao.findLogs()
        if (logs.isEmpty()) {
            return
        }

        val ids = logs.map  { it.id }
        appLogDao.updateStatus(ids, 1 )
        try {
            val response = ApiDataSource.instance.applog(logs)
            if (response.isSuccess) {
                appLogDao.updateSuccess(ids, System.currentTimeMillis())
            } else {
                appLogDao.updateFail(ids, response.codeAndMessage)
                XLog.e("worker.upload device log fail:%s", response.codeAndMessage)
            }
        } catch (e: Exception) {
            appLogDao.updateFail(ids, e.message?: "request failed")
            XLog.e("worker.upload device log fail:%s", e.message)
        }

        //删除15天前的log
        val time = System.currentTimeMillis() - 15 * 24 * 60 * 1000L
        appLogDao.deleteOldData(time)
    }

    private fun startWorker() {
        val periodicWorkRequest = PeriodicWorkRequestBuilder<AppLogWorker>(10, TimeUnit.MINUTES)
            .setConstraints(
                Constraints.Builder()
                    .setRequiredNetworkType(NetworkType.CONNECTED)
                    .build()
            )
            .setInitialDelay(1, TimeUnit.MINUTES) // 初始延迟1分钟
            .addTag("periodic_app_log_upload")
            .build()
        XLog.d("enqueue AppLogWorker")
        WorkManager.getInstance(MyApplication.app.applicationContext).enqueueUniquePeriodicWork(
            "periodic_app_log_upload",
            ExistingPeriodicWorkPolicy.UPDATE,
            periodicWorkRequest
        )
    }


}